#include <linux/module.h> 
#include <linux/fs.h>//添加和注销,设备驱动程序提供入口点 
#include <asm/io.h>//对设备进行管理的函数入口 
#include <linux/init.h> 
#include <linux/kernel.h>//内存操作 
#include <linux/cdev.h> 
#include <linux/moduleparam.h>//定义模块可以传递参数 
#include <asm/arch/regs-gpio.h>//GPIO口相关的宏定义 
#include <asm/hardware.h>//GPIO口操作相关的函数定义 
#include <asm/arch/regs-timer.h>//S3C2410_TCFG等的定义

#define	PWM_NAME "fl2440_pwm"
#define DEVICE_MAJOR 230

int devno;
 
struct pwm_dev {  
	struct cdev cdev; 
}pwm1_dev;
 
static int pwm_open(struct inode *inode, struct file *filp)//打开设备进行I/O操作 
{ 
     //对GPB0复用扣进行复用功能的设置，设置为TOUT0 PWM输出 
    s3c2410_gpio_cfgpin(S3C2410_GPB0,S3C2410_GPB0_TOUT0);//S3C2410_GPB0_TOUT0   (0x02 << 0) 
	return 0; 
}
 
static int pwm_close(struct inode *inode, struct file *filp)//关闭设备并释放资源 
{ 
     return 0; 
}
 
static int pwm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) 
{
    if(cmd == 0)//如果cmd等于0，则让蜂鸣器停止工作      
	{ 
        s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_OUTP);//GPB0口为输出口 
        s3c2410_gpio_setpin(S3C2410_GPB0, 0);//低电平，停止      
	} 
    else //输入的参数大于0，就让蜂鸣器开始工作，不同的参数，蜂鸣器的频率不一样 
    {
		unsigned long tcnt = 0;   
		unsigned long tcon = 0;   
		unsigned long tcfg0 = 0;   
		unsigned long tcfg1 = 0;   
		unsigned long pclk = 0;   
		tcfg0 = __raw_readl(S3C2410_TCFG0);   
		tcfg1 = __raw_readl(S3C2410_TCFG1);
		tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;//S3C2410_TCFG_PRESCALER0_MASK = 255 
		tcfg0 |= (50-1);   
		tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK;//S3C2410_TCFG1_MUX0_MASK = 15 << 0 
		tcfg1 |= S3C2410_TCFG1_MUX0_DIV4;   
		__raw_writel(tcfg0,S3C2410_TCFG0);   
		__raw_writel(tcfg1,S3C2410_TCFG1);   
		pclk = 10000000;   
		tcnt = (pclk/50/4)/cmd;//计算定时器0的输出时钟频率(pclk/{prescaler0 + 1}/divider value) 
		__raw_writel(tcnt,S3C2410_TCNTB(0));   
		__raw_writel(tcnt/2,S3C2410_TCMPB(0));   
		tcon = __raw_readl(S3C2410_TCON);   
		tcon &= ~0x1f;   tcon |= 0xb;   
		__raw_writel(tcon,S3C2410_TCON);   
		tcon &= ~0x2;    
		__raw_writel(tcon,S3C2410_TCON);//清除定时器0的手动更新位
	}   
	return 0; 
}

static struct file_operations pwm_fops = //设备操作结构体,文件系统接口定义 
{ 
	.owner = THIS_MODULE,      
	.open = pwm_open,      
	.release = pwm_close,      
	.ioctl = pwm_ioctl, 
};
 
static int __init pwm_init(void) {     
	int ret, err; 
	ret = register_chrdev(DEVICE_MAJOR, DEVICE_NAME, &s3c2440_leds_fops);
	if (ret < 0) {
		printk(DEVICE_NAME " can't register major number\n");
		return ret;
	}

	devfs_mk_cdev(MKDEV(DEVICE_MAJOR, 0), S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,DEVICE_NAME);  
	ret = alloc_chrdev_region(&devno,0,1,PWM_NAME); //在内核中注册设备  
	if (ret < 0){   
		printk(PWM_NAME "register failure!\n");     
		return ret;  
	}else{   
		printk(PWM_NAME " register success!\n");    
		cdev_init(&pwm1_dev.cdev,&pwm_fops);   
		pwm1_dev.cdev.owner = THIS_MODULE;   
		pwm1_dev.cdev.ops = &pwm_fops;   
		err = cdev_add(&pwm1_dev.cdev,devno,1);//创建设备节点   
		if (err){    
			printk(PWM_NAME " Add failure!\n");   
		}else{    
			printk(PWM_NAME " Creat success!\n");   
		}
	}  
	return 0; 
}
     
static void __exit pwm_exit(void) {
	unregister_chrdev_region(devno,1);//注销设备  
	cdev_del(&pwm1_dev.cdev);//删除设备节点  
	printk(PWM_NAME "unregister success!\n"); 
}
 
module_init(pwm_init);//模块化  
module_exit(pwm_exit);
 
MODULE_LICENSE("GPL");//宏声明此模块的许可证  
MODULE_AUTHOR("wangyijieonline@126.com"); 
MODULE_DESCRIPTION("fl2440 pwm driver");